package controllers

import (
	"encoding/json"
	"github.com/pkg/errors"
	"github.com/spf13/cast"
	"nft-server/common"
	"nft-server/dao"
	"nft-server/db"
	"nft-server/errcode"
	"nft-server/logger"
	"nft-server/model"
	"nft-server/payment"
	"nft-server/service"
	"nft-server/util"
	"time"
)

const (
	QueryOrderURI  = "/v1/order/query"
	CancelOrderURI = "/v1/order/cancel"
)

type OrderController struct {
	CommonController
}

//CheckParameterForQueryOrder 用于QueryOrder校验参数
func (oc *OrderController) CheckParameterForQueryOrder(req *common.OrderQueryReq) (userId string, role string, userName string, err error) {
	if req.Page <= 0 || req.PageSize <= 0 {
		err = errors.Errorf("页面和页码必须大于零")
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage(err.Error()))
		return "", "", "", err
	}
	userInfo := oc.GetSession(common.SessionUserId)
	if userInfo == nil {
		err = errors.Errorf("Failed to get userId from session id")
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("该用户不存在"))
		return "", "", "", err
	}
	userId = cast.ToString(userInfo.(int))
	sessionUserName := oc.GetSession(common.SessionUserName)
	if sessionUserName == nil {
		err = errors.Errorf("Failed to get userId from session id")
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("该用户不存在"))
		return "", "", "", err
	}
	userName = cast.ToString(sessionUserName.(string))
	roleValue := oc.GetSession(common.SessionRole)
	if roleValue == nil {
		err := errors.Errorf("Failed to get role from session id")
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("该用户不存在"))
		return "", "", "", err
	}
	role = cast.ToString(roleValue.(string))
	if req.UserId != cast.ToInt(userId) {
		err = errors.Errorf("Failed to get same userId from session id.")
		logger.Error(err.Error())
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("该用户不存在"))
		return "", "", "", err
	}
	if util.InArray(req.OrderStatusFlag, util.ValidOrderStatusFlag) == false {
		err = errors.Errorf("Invaild orderStatusFlag:%v.", req.OrderStatusFlag)
		logger.Error(err.Error())
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("无效的订单标志位"))
		return "", "", "", err
	}
	req.OrderStatus = util.GetOrderStatusArray(req.OrderStatusFlag)
	return userId, role, userName, nil
}

//BuildCollectionConditionForQueryOrder 为了在QueryOrder函数中从请求参数中构造出用于查询集合的条件
func (oc *OrderController) BuildCollectionConditionForQueryOrder(req *common.OrderQueryReq, role string, userId string) (collections []*model.CollectionDetail, err error) {
	//管理员可以查看所有订单
	//普通用户只能查看自己的订单
	if role == service.UserRoleName {
		req.Role = service.UserRoleName
		req.UserId = cast.ToInt(userId)
	}
	//通过collectionName和issuer查找对应collectionIndex
	collection := new(model.CollectionDetail)
	adminId, err := service.GetAdminId()
	if err != nil {
		logger.Error(err.Error())
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("查找订单失败"))
		return nil, nil
	}
	//暂时所有集合都处于管理员名下
	//集合名和issuer名称以相同参数查询
	req.Issuer = req.CollectionName
	collection.UserId = adminId
	collection.CollectionName = req.CollectionName
	collection.Issuer = req.Issuer
	collection.CollectionStatus = util.DefaultCollectionStatus
	collections, err = service.GetCollectionNamesForOrderQuery(collection)
	if err != nil {
		logger.Error(err.Error())
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("查找订单失败"))
		return nil, nil
	}
	return collections, nil
}

// QueryOrder  查询订单信息表
func (oc *OrderController) QueryOrder() {
	//请求头--put
	req := common.OrderQueryReq{}
	if err := json.Unmarshal(oc.Ctx.Input.RequestBody, &req); err != nil {
		logger.Error("QueryOrder Unmarshal error: %v", err)
		oc.HandleErrCode(errcode.E.Base.RequestInvalid.WithErr(err))
		return
	}
	//CheckParameterForQueryOrder处理了错误和日志,queryOrder为最终用于查询订单的条件
	userId, role, userName, err := oc.CheckParameterForQueryOrder(&req)
	if err != nil || len(role) == 0 || len(userId) == 0 {
		return
	}
	collections, err := oc.BuildCollectionConditionForQueryOrder(&req, role, userId)
	if err != nil || collections == nil {
		return
	}
	nowTime := time.Now()
	//懒加载
	overTimeUserId := ""
	if role == service.UserRoleName {
		overTimeUserId = string(req.UserId)
	}
	//查询检查超时订单进行关闭
	err = service.CheckOverTimeOrder(overTimeUserId, nowTime)
	if err != nil {
		logger.Error(err.Error())
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("查找订单失败"))
		return
	}
	req.CollectionIndex, _ = service.GetCollectionIndexFromArray(collections)
	orders, size, totalNum, err := service.GetAllOrderWithPage(&req, nowTime)
	if err != nil {
		logger.Error(err.Error())
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("查找订单失败"))
		return
	}
	response := common.OrderInfoForQuery{}
	response.OrderSize = size
	response.TotalNum = totalNum
	err = service.ConstructOrderInfo(userName, &response, orders)
	if err != nil {
		logger.Error(err.Error())
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("查找订单失败"))
		return
	}
	oc.HandleBusinessObj(response)
}
func (oc *OrderController) CheckParameterForCancelOrder(req common.OrderReq) error {
	userId := ""
	if len(req.OrderId) <= 0 {
		err := errors.Errorf("CancelOrder error: orderId can't be found.")
		oc.HandleErrCode(errcode.E.Base.RequestInvalid.WithMessage("请求订单号错误"))
		return err
	} else {
		userInfo := oc.GetSession(common.SessionUserId)
		if userInfo == nil {
			err := errors.Errorf("Failed to get userId from session id")
			oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("该用户不存在"))
			return err
		}
		userId = cast.ToString(userInfo.(int))
	}
	if len(userId) < 1 || cast.ToString(req.UserId) != userId {
		err := errors.Errorf("Failed to get same userId from session id.")
		logger.Error(err.Error())
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("该用户不存在"))
		return err
	}
	return nil
}

// CancelOrder 关闭订单
func (oc *OrderController) CancelOrder() {
	req := common.OrderReq{}
	req.OrderId = oc.Ctx.Input.Query("orderId")
	req.UserId = cast.ToInt(oc.Ctx.Input.Query("userId"))
	err := oc.CheckParameterForCancelOrder(req)
	if err != nil {
		return
	}
	//从缓存中删除订单
	order, err := service.DeleteOrderFromRedis(req.UserId, db.RedisPool)
	if err != nil {
		logger.Error("CancelOrder error: %v", err)
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("删除缓存订单失败"))
		return
	} else if err == nil && order == nil {
		logger.Info("CancelOrder error: %v", err)
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("订单已支付或已关闭"))
		return
	}
	if util.InStringArray(order.OrderStatus, service.OrderStatusCanClose) == false {
		logger.Error("CancelStatus error: order(id:%v) can't be close.", req.OrderId)
		oc.HandleErrCode(errcode.E.Base.RequestInvalid.WithMessage("当前订单不可关闭"))
		return
	}
	err = payment.ExampleCloseOrder(req.OrderId)
	if err != nil {
		logger.Error("CancelOrder error: %v", err)
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("第三方关闭订单失败"))
		return
	}
	// 平台内修改订单状态为已关闭
	oldOrder, err := dao.GetOrderDao().GetOrderByOrderId(req.OrderId)
	err = service.UpdateOrderStatus(oldOrder, util.TradeClosed)
	if err != nil {
		logger.Error("CancelOrder error: %v", err)
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("系统关闭订单失败"))
		return
	}
	//写回库存
	err = service.WriteOneTokenIntoRedis(order.CollectionIndex, order.SubCollectionIndex, order.TokenId, db.RedisPool)
	if err != nil {
		logger.Error("CancelOrder error: %v", err)
		oc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("写回库存失败"))
		return
	}
	oc.HandleBusinessSuccess()
}
